面白そうだったのでHTTPS通信パケットを復号してみました。HTTPS通信パケットを復号するにあたり、まずはHTTPSの暗号化方式について調べてみたのでまとめます。
HTTPSの暗号化方式
HTTPS通信の暗号化には公開鍵暗号方式と共通鍵暗号方式の両方を利用したハイブリッド方式により暗号化が行われます。それぞれの暗号化方式についての説明です。
・共通鍵暗号方式
共通鍵暗号方式では、サーバー側もクライアント側も、データの暗号化と復号に同じ鍵を使用します。この方式のメリットは処理時間が短いことです。一方でデメリットとしてサーバーとクライアントで鍵を交換する際に、鍵を盗まれる危険性があります。下の図はすでに鍵交換を終えて、データをやり取りしている状態の図です。どうやって鍵を交換するかまでは、この暗号方式では特に決まっていません。
・公開鍵暗号方式
公開鍵暗号方式は、送受信データの暗号化と復号に異なる鍵(公開鍵と秘密鍵)を使用します。サーバ側が秘密鍵を持ち、クライアント側が公開鍵を持ちます。公開鍵で暗号化されたデータは秘密鍵でしか復号できません。反対に秘密鍵で暗号化されたデータは、公開鍵でしか復号できません。
公開鍵暗号方式のメリットは鍵の配布が簡単に行えることです。公開鍵は、名前の通り公開された状態にありますが、上記の特性により送受信データの機密性は保つことができます。一方で、この方式のデメリットは、共通鍵暗号方式に比べて処理時間が長くなることです。下の図はサーバから、クライアントが公開鍵を受け取った後の図になります。
・ハイブリッド方式
ハイブリッド暗号方式は、共通鍵暗号方式と公開鍵暗号方式を組み合わせた暗号方式になります。共通鍵暗号方式では、どうやって安全に鍵を交換するかが問題になっていました。ハイブリッド方式では、その問題に対して公開鍵暗号方式を使います。共通鍵を、公開鍵暗号方式により暗号化し、安全に鍵を交換します。共通鍵の交換後は、送受信データの暗号化と復号にその共通鍵を使います。これにより公開鍵暗号方式で問題だった、処理時間が長くなるのを防ぐことができます。
このようにハイブリッド方式は、共通鍵暗号方式と公開鍵暗号方式のメリットを併せ持つ暗号方式になります。HTTPS通信ではこの暗号方式が利用されています。下の図は一つ目が共通鍵を交換する様子で、二つ目が送受信データの暗号化と復号の様子です。
TLSハンドシェイクについて
サーバーとクライアントはHTTPS通信を開始する際に、まず鍵の交換を行います。この公開鍵と秘密鍵を使って、共通鍵を交換する過程を「TLSハンドシェイク」と言います。
TLSハンドシェイクでは、以下のような手順を通して、サーバの認証や暗号化通信の準備も行います。その中でも今回は共通鍵の生成に重要な部分のみを見ていきます。
- Client Hello
- Server Hello
- Server Certificate
- Server Key Exchange
- Certificate Request
- Server Hello Done
- Client Certificate
- Client Key Exchange
- Certificate Verify
- Change Cipher Spec
- Finished
- Change Cipher Spec
- Finished
TLSハンドシェイクの中で共通鍵が生成される過程を図に表しました。共通鍵の生成には、サーバーとクライアントのそれぞれが生成した「乱数」と、「プリマスタシークレット」が利用されます。
・「1. Client Hello」,「2. Server Hello」
サーバー、クライアントがそれぞれ生成した「乱数」が送受信されます。
・「3. Server Certificate」,「4. Server Key Exchange」
大抵の場合「3. Server Certificate」でサーバーはSSLサーバ証明書と一緒に、公開鍵をクライアントへ送信します。しかし、もしサーバー側が証明書を持っていない場合や、証明書に公開鍵が含まれていない場合は「4. Server Key Exchange」のメッセージが送信されて、そこで公開鍵が送信されます。
・「8. Client Key Exchange」
クライアント側は「プリマスタシークレット」と呼ばれる乱数を生成し、先ほど受け取った公開鍵で暗号化します。そして暗号化したプリマスタシークレットをサーバーへ送信します。受信したサーバー側は秘密鍵でプリマスタシークレットを復号します。
・TLSセッションキー(共通鍵)の生成
これで双方に「プリマスタシークレット」と二つの「乱数」が揃いました。この三つが共通鍵を作る前々段階の情報になります。次にサーバー側、クライアント側はどちらもプリマスタシークレットと乱数から「マスターシークレット」を生成します。マスターシークレットが共通鍵を生成する前段階の情報になります。その後、クライアントとサーバーは、マスタシークレットから「MACシークレット」と「TLSセッションキー(共通鍵)」を作成します。これで鍵交換が完了したため、以降の通信は共通鍵で暗号化されます。
鍵情報からHTTPS通信パケットを復号してみた
Wiresharkなどを使うと通信パケットをキャプチャすることができます。HTTPS通信は暗号化されているため、Wiresharkでも読めません。ですが、通信パケットと一緒に共有鍵もキャプチャすることで通信内容を確認できます。今回はChromeのHTTPS通信を復号してみました。Chromeには最初から開発者ツールがあり、通信内容はそれで確認できるのであまり実用性はありません。
以下のコマンドのように環境変数を指定して、Chromeを起動すると鍵情報を保存することができます。
$ SSLKEYLOGFILE=~/Desktop/tls_key.log "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
Wiresharkを起動してパケットキャプチャを開始します。さっきコマンドから起動したChromeでhttps://から始まるURLにアクセスします。
Wireshark上ではパケットをキャプチャしていますが、通信が暗号化されているため通信内容までは分かりません。様々なパケットが表示されていますが、HTTPSの通信だけを表示するためフィルターに「HTTP2」を入力します。しかし、今はまだ復号できていないため何も表示されません。HTTPSのパケットは復号が行われていない状態だとTCPとして表示されるためです。
次に復号を行います。まず画面上部のツールバーから、Wireshark > Preferences を開きます。開いたウィンドウの左側の項目の中から Protocols > TLS の順に選択します。 (Pre)-Master-Secret log filenameの項目に鍵情報のファイルを指定します。
さっきまでHTTP2のフィルターをかけると何も表示されませんでしたが、今度は表示されています。
これで復号が行えました。